

// https://blog.csdn.net/sflf36995800/article/details/82263221
// 原项目地址regex-cache <https://github.com/think2011/ref-line>
// 筷子改造后项目地址 <https://github.com/Kuaizi-co/ref-line>

function createRefline(el) {
  let lines = {
    xt: null,
    xc: null,
    xb: null,
    yl: null,
    yc: null,
    yr: null,
  }
  
  // 置入参考线
  for (let p in lines) {
    let node = lines[p] = document.createElement('div')
  
    node.classList.add('ref-line', p)
    node.style.cssText = `display:none;opacity:0.7;position:absolute;background:#4DAEFF;z-index:9999;${p[0] === 'x' ? 'width:100%;height:1px;left:0;' : 'width:1px;height:100%;top:0;'}`
  
    // 挂上一些辅助方法
    node.show = function () {
      this.style.display = 'block'
    }
    node.hide = function () {
      this.style.display = 'none'
    }
    node.isShow = function () {
      return this.style.display !== 'none'
    }
    el ? el.appendChild(node) : document.body.appendChild(node)
  }
  
  return lines
}
class RefLine {
  constructor(el, options = {}) {
    this.options = Object.assign({
      gap: 3
    }, options)
    this.lines = createRefline(el);
  }

  /**
   * @param dragNode {Element} 拖拽元素的原生node
   * @param checkNodes {String|Element} 选择器 或者 原生node集合
   */
  check(dragNode, checkNodes) {
    checkNodes = typeof checkNodes === 'string' ? document.querySelectorAll(checkNodes) : checkNodes;
    let dragRect = {
      width: dragNode.offsetWidth,
      height: dragNode.offsetHeight,
      top: dragNode.offsetTop,
      left: dragNode.offsetLeft,
      right: dragNode.offsetLeft + dragNode.offsetWidth,
      bottom: dragNode.offsetHeight + dragNode.offsetTop,
    };

    this.uncheck();
    Array.from(checkNodes).forEach((item) => {
      item.classList.remove('ref-line-active')

      if (item === dragNode) return; // 排除自己

      const itemRect = {
        width: item.offsetWidth,
        height: item.offsetHeight,
        top: item.offsetTop,
        left: item.offsetLeft,
        right: item.offsetLeft + item.offsetWidth,
        bottom: item.offsetHeight + item.offsetTop,
     }
      let { top, height, bottom, left, width, right } = itemRect
      let dragWidthHalf = dragRect.width / 2
      let itemWidthHalf = width / 2
      let dragHeightHalf = dragRect.height / 2
      let itemHeightHalf = height / 2

      let conditions = {
        top: [
          // xt-top 辅助线出现在非拖拽item的上方 拖拽元素的上方
          {
            isNearly: this._isNearly(dragRect.top, top),
            lineNode: this.lines.xt,
            lineValue: top,
            dragValue: top
          },
          // xt-bottom 辅助线出现在非拖拽item的上方 拖拽元素的下方
          {
            isNearly: this._isNearly(dragRect.bottom, top),
            lineNode: this.lines.xt,
            lineValue: top,
            dragValue: top - dragRect.height
          },
          // xc 中心线
          {
            isNearly: this._isNearly(dragRect.top + dragHeightHalf, top + itemHeightHalf),
            lineNode: this.lines.xc,
            lineValue: top + itemHeightHalf,
            dragValue: top + itemHeightHalf - dragHeightHalf
          },
          // xb-top 辅助线出现在非拖拽item的下方 拖拽元素的下方
          {
            isNearly: this._isNearly(dragRect.bottom, bottom),
            lineNode: this.lines.xb,
            lineValue: bottom,
            dragValue: bottom - dragRect.height
          },
          // xb-bottom 辅助线出现在非拖拽item的下方 拖拽元素的上方
          {
            isNearly: this._isNearly(dragRect.top, bottom),
            lineNode: this.lines.xb,
            lineValue: bottom,
            dragValue: bottom
          },
        ],

        left: [
          // yl-left 辅助线出现在非拖拽item的左方 拖拽元素的左方
          {
            isNearly: this._isNearly(dragRect.left, left),
            lineNode: this.lines.yl,
            lineValue: left,
            dragValue: left
          },
          // yl-right 辅助线出现在非拖拽item的左方 拖拽元素的右方
          {
            isNearly: this._isNearly(dragRect.right, left),
            lineNode: this.lines.yl,
            lineValue: left,
            dragValue: left - dragRect.width
          },
          // yc 中心线
          {
            isNearly: this._isNearly(dragRect.left + dragWidthHalf, left + itemWidthHalf),
            lineNode: this.lines.yc,
            lineValue: left + itemWidthHalf,
            dragValue: left + itemWidthHalf - dragWidthHalf
          },
          // yr-left 辅助线出现在非拖拽item的右方 拖拽元素的右方
          {
            isNearly: this._isNearly(dragRect.right, right),
            lineNode: this.lines.yr,
            lineValue: right,
            dragValue: right - dragRect.width
          },
          // yr-right 辅助线出现在非拖拽item的右方 拖拽元素的左方
          {
            isNearly: this._isNearly(dragRect.left, right),
            lineNode: this.lines.yr,
            lineValue: right,
            dragValue: right
          },
        ]
      }

      for (let key in conditions) {
        // 遍历符合的条件并处理
        conditions[key].forEach((condition) => {
          if (!condition.isNearly) return

          item.classList.add('ref-line-active')
          dragNode.style[key] = `${condition.dragValue}px`
          condition.lineNode.style[key] = `${condition.lineValue}px`
          condition.lineNode.show()
        })
      }
    })
  }

  uncheck() { // 取消参考线
    Object.values(this.lines).forEach((item) => item.hide())
    Array.from(document.querySelectorAll('.ref-line-active')).forEach((item) => item.classList.remove('ref-line-active'))
  }

  _isNearly(dragValue, targetValue) { // 吸附
    return Math.abs(dragValue - targetValue) <= this.options.gap
  }
}